#ifndef __UTIL_HPP__
#define __UTIL_HPP__
// 实用文件

#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <atomic>
#include <fstream>
#include <vector>
#include <boost/algorithm/string.hpp>  // boost库，C++准标准库

namespace ns_util
{
    const std::string path = "./temp/";
    // 合并路径类
    class PathUtil
    {
    public:
        // 拼接函数
        static std::string splic(const std::string& str1, const std::string& str2)
        {
            std::string temp = path;
            temp += str1;
            temp += str2;
            return temp;
        }

        // 编译临时文件
        // 拼接源文件 文件名+cpp
        static std::string Src(const std::string& file_name)
        {
            return splic(file_name, ".cpp");
        }

        // 拼接可执行文件 文件名+exe
        static std::string Exe(const std::string& file_name)
        {
            return splic(file_name, ".exe");
        }

        // 拼接保存标准错误文件
        static std::string CompileError(const std::string& file_name)
        {
            return splic(file_name, ".compile_error");
        }

        // 运行临时文件
        // 拼接保存标准输入文件
        static std::string Stdin(const std::string& file_name)
        {
            return splic(file_name, ".stdin");
        }

        // 拼接保存标准输出文件
        static std::string Stdout(const std::string& file_name)
        {
            return splic(file_name, ".stdout");
        }

        // 拼接保存标准错误文件
        static std::string Stderr(const std::string& file_name)
        {
            return splic(file_name, ".stderr");
        }
    };

    // 时间相关类
    class TimeUtil
    {
    public:
        static std::string GetTimeStamp()
        {
            // 使用系统调用gettimeofday
            struct timeval t;
            gettimeofday(&t, nullptr);  // 获取时间戳的结构体、时区
            return std::to_string(t.tv_sec);
        }

        // 获取毫秒级时间戳
        static std::string GetTimeMs()
        {
            struct timeval t;
            gettimeofday(&t, nullptr);
            return std::to_string((t.tv_sec * 1000 + t.tv_usec / 1000)); // 秒+微秒
        }
    };

    // 文件相关类
    class FileUtil
    {
    public:
        // 判断传入文件（完整路径）是否存在
        static bool IsFileExist(const std::string& pathFile)
        {
            // 使用系统调用stat查看文件属性，查看成功说明存在文件，否则没有
            struct stat st;
            if (stat(pathFile.c_str(), &st) == 0)
            {
                // 说明存在文件
                return true;
            }
            return false;  // 否则不存在此文件
        }

        // 生成唯一的文件名
        // 利用微秒时间戳和原子性的唯一增长数字组成
        static std::string UniqueFileName()
        {
            // 利用C++11的特性，生成一个原子性的计数器
            static std::atomic_uint id(0);
            id++;
            std::string ms = TimeUtil::GetTimeMs();
            return ms + "-" + std::to_string(id);
        }

        // 根据路径文件进行写入
        static bool WriteFile(const std::string& path_file, const std::string& content)
        {
            // 利用C++的文件流进行简单的操作
            std::ofstream out(path_file);
            // 判断此文件是否存在
            if (!out.is_open()) return false;
            out.write(content.c_str(), content.size());
            out.close();
            return true;
        }

        // 根据路径文件进行读出
        // 注意，默认每行的\\n是不进行保存的，需要保存请设置参数
        static std::string ReadFile(const std::string& path_file, bool keep = false)
        {
            // 利用C++的文件流进行简单的操作
            std::string content, line;
            std::ifstream in(path_file);
            if (!in.is_open()) return "";
            while (std::getline(in, line))
            {
                content += line;
                if (keep) content += "\n";
            }
            in.close();
            return content;
        }
    };

    // 字符串相关工具类
    class StringUtil
    {
    public:
        // 切割字符串，保存入vector中
        static void SpiltString(const std::string& src, std::vector<std::string>& target, std::string op)
        {
            boost::split(target, src, boost::is_any_of(op), boost::algorithm::token_compress_on);  // 数组、遇到对应分隔符全部切割 压缩（切割出来的空串删除）
        }
    };
}

#endif